package com.ziytek.web.citizen.service;

import com.google.gson.Gson;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.JobConstant;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.mapper.BoardConfigMapper;
import com.ziytek.web.citizen.mapper.OperationDetailMapper;
import com.ziytek.web.citizen.model.bean.CommandFirst;
import com.ziytek.web.citizen.model.bean.CronJob;
import com.ziytek.web.citizen.model.bean.JobTimes;
import com.ziytek.web.citizen.model.rsp.R;
import com.ziytek.web.citizen.quartz.QuartzService;
import com.ziytek.web.citizen.util.KeyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * 定时任务实现
 *
 * @author fenghx
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class JobReStartService {
    private final Gson gson;
    private final QuartzService quartzService;
    private final BoardConfigMapper boardConfigMapper;
    private final OperationDetailMapper operationDetailMapper;
    private final OperationVoCacheService operationVoCacheService;

    public boolean singleChannelJob(CommandFirst command) {
        Assert.notNull(command, "commandIssuedSuccess is null");
        if (command.getExpectedTimeSecond() == null) {
            log.info("添加定时任务失败，时间不能为空:{}", gson.toJson(command));
            return false;
        }

        var order = command.getOrder();
        var boardNo = command.getBoardNo();
        var channelNo = command.getChannelNo();
        var expectedTimeSecond = command.getExpectedTimeSecond();
        var cabinetNo = Integer.parseInt(command.getReqCabinetNo());
        var interruptOrEndStepId = command.getInterruptOrEndStepId();

        var isStop = command.getStepId() != null && NumConstant.LONG_LT_ZERO == command.getStepId();
        var bc = boardConfigMapper.queryByChannelNo(boardNo, channelNo);
        if (bc == null) {
            log.info("添加定时任务失败,查询board信息为空:{}-{}-{}", command, boardNo, channelNo);
            return false;
        }

        // 获取操作记录缓存信息
        var ky = KeyUtil.commandOperateKey(cabinetNo, bc.getAddress(), bc.getChannelNo());
        var vo = operationVoCacheService.getOperationVo(ky);
        var commandType = vo != null && StringUtils.isNotEmpty(vo.getSetType()) ? vo.getSetType() : "";

        // 查询是否是异常状态
        var op = operationDetailMapper.findOneDetailByCellNum(String.valueOf(cabinetNo), boardNo, command.getChannelNo());
        log.info("添加定时任务查询操作记录缓存信息:{}", gson.toJson(op));
        if (null != op && ServerConstant.START_FLAG_ERROR == op.getStartFlag()) {
            if (NumConstant.INT_ONE == order) {
                // 异常只储存第一帧数据 定时任务删除及重启
                log.info("[order==1]时操作状态为99异常状态只储存第一次异常记录:{}-{}-{}-{}-{}", cabinetNo, boardNo, channelNo, gson.toJson(command), gson.toJson(vo));
                return jobReStart(commandType, cabinetNo, boardNo, channelNo, order, NumConstant.INT_ZERO, interruptOrEndStepId, isStop, true);
            }

            log.info("添加定时任务失败,查询操作状态为99异常状态:{}-{}-{}-{}-{}", cabinetNo, boardNo, channelNo, gson.toJson(command), gson.toJson(vo));
            return false;
        }

        // 定时任务删除及重启
        return jobReStart(commandType, cabinetNo, boardNo, channelNo, order, expectedTimeSecond, interruptOrEndStepId, isStop, false);
    }


    private boolean jobReStart(String commandType, int cabinetNo, int boardNo, int channelNo, int order, int expectedTimeSecond, Long interruptOrEndStepId, boolean isStop, boolean orderOneFirstError) {
        // 第三、设置电池数据定时保存定时任务
        var key = CaffeineUtil.getCacheKey(cabinetNo, boardNo, channelNo);
        var deleteKey = CaffeineUtil.getCacheKey(cabinetNo, boardNo, channelNo);

        var jobName = JobConstant.JOB_NAME_COMMAND + CaffeineUtil.CACHE_KEY_SYMBOL + key;
        var deleteJobName = JobConstant.JOB_NAME_COMMAND + CaffeineUtil.CACHE_KEY_SYMBOL + deleteKey;
        var triggerName = JobConstant.TRIGGER_NAME_COMMAND + key;
        var jobClassName = "com.ziytek.web.citizen.quartz.execute.StepIssuedEventListenerQuartzJob";

        var cronJob = new CronJob();
        cronJob.setJobName(jobName);
        cronJob.setTriggerName(triggerName);
        cronJob.setJobClassName(jobClassName);
        cronJob.setExpectedTimeSecond(expectedTimeSecond);
        cronJob.setOrderOneFirstError(orderOneFirstError);
        var jobDataMap = new JobDataMap();
        var jobTimes = new JobTimes();
        jobTimes.setOrderNo(order);
        jobTimes.setBoardNo(boardNo);
        jobTimes.setCabinetNo(cabinetNo);
        jobTimes.setChannelNo(channelNo);
        jobTimes.setCommandType(commandType);
        jobTimes.setTimes(NumConstant.INT_ZERO);
        jobTimes.setOrderOneFirstError(orderOneFirstError);
        jobTimes.setInterruptOrEndStepId(interruptOrEndStepId);
        jobTimes.setSingeType(ServerConstant.SINGLE_TYPE_SINGLE);

        jobDataMap.put(ServerConstant.JOB_TIMES, jobTimes);
        cronJob.setDataMap(jobDataMap);

        R r = quartzService.deleteCronJob(deleteJobName);
        if (r == null || !ServerConstant.SUCCESS.equals(r.getCode())) {
            log.info("删除定时任务失败 jobName:{},result:{}", deleteJobName, gson.toJson(r));
        }

        r = quartzService.deleteCronJob(jobName);
        if (r == null || !ServerConstant.SUCCESS.equals(r.getCode())) {
            log.info("删除定时任务失败 jobName:{},result:{}", jobName, gson.toJson(r));
        }

        if (isStop) {
            return true;
        }

        var cacheKey = cabinetNo + CaffeineUtil.CACHE_KEY_SYMBOL + boardNo + CaffeineUtil.CACHE_KEY_SYMBOL + channelNo;
        cronJob.setCacheKey(cacheKey);
        r = quartzService.addCronJob(cronJob);
        if (r == null || !ServerConstant.SUCCESS.equals(r.getCode())) {
            log.info("添加定时任务失败 cronJob:{},result:{}", gson.toJson(cronJob), gson.toJson(r));
        }

        //log.info("添加定时任务结果 cronJob：{} r:{}", gson.toJson(cronJob), gson.toJson(r));
        return r != null && ServerConstant.SUCCESS.equals(r.getCode());
    }
}
